package com.eastfair.pay.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.alibaba.fastjson.JSONObject;
//import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.eastfair.annotation.annotation.cache.Cache;
import com.eastfair.annotation.annotation.cache.Magic;
import com.eastfair.boot.service.SuperServiceImpl;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.core.base.R;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.exception.BizException;
import com.eastfair.database.mybatis.conditions.Wraps;
import com.eastfair.database.mybatis.conditions.query.QueryWrap;
import com.eastfair.pay.chinaums.CScanB.CScanBQuery;
import com.eastfair.pay.chinaums.CScanB.CScanBRefund;
import com.eastfair.pay.chinaums.CScanB.CScanBRefundQuery;
import com.eastfair.pay.chinaums.CScanB.GetQrCode;
import com.eastfair.pay.chinaums.MiniPay.UnifiedOrder;
import com.eastfair.pay.chinaums.MiniPay.UnifiedQuery;
import com.eastfair.pay.chinaums.MiniPay.UnifiedRefund;
import com.eastfair.pay.chinaums.MiniPay.UnifiedRefundQuery;
import com.eastfair.pay.chinaums.uac.UpgOrder;
import com.eastfair.pay.chinaums.uac.UpgQuery;
import com.eastfair.pay.chinaums.uac.UpgRefund;
import com.eastfair.pay.chinaums.uac.UpgRefundQuery;
import com.eastfair.pay.chinaums.webPay.WebPay;
import com.eastfair.pay.chinaums.webPay.WebQuery;
import com.eastfair.pay.chinaums.webPay.WebRefund;
import com.eastfair.pay.chinaums.webPay.WebRefundQuery;
import com.eastfair.pay.dao.ChinaumsLogMapper;
import com.eastfair.pay.dto.*;
import com.eastfair.pay.entity.ChinaumsLog;
import com.eastfair.pay.entity.TransactionOrder;
import com.eastfair.pay.enumeration.ChinaumsLogRequestTypeEnum;
import com.eastfair.pay.enumeration.TransactionOrderOrderStatusEnum;
import com.eastfair.pay.enums.ChinaumsStatusEnum;
import com.eastfair.pay.enums.InstMidEnum;
import com.eastfair.pay.enums.PayTypeEnum;
import com.eastfair.pay.enums.RefundStatusEnum;
import com.eastfair.pay.exceptioncode.PayExceptionCode;
import com.eastfair.pay.service.ApplyRefundService;
import com.eastfair.pay.service.ChinaumsLogService;
import com.eastfair.pay.service.TransactionOrderService;
import com.eastfair.pay.vo.ChinaumsLogVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 业务实现类
 * 调用银联日志
 * </p>
 *
 * @author linan
 * @date 2023-05-05
 */
@Slf4j
@Service
//@DS("#thread.tenant")
public class ChinaumsLogServiceImpl extends SuperServiceImpl<ChinaumsLogMapper, ChinaumsLog> implements ChinaumsLogService {

    public static final String SUCCESS = "SUCCESS";
    public static final String QRPAYDEFAULT = "QRPAYDEFAULT";
    public static final String YUEDANDEFAULT = "YUEDANDEFAULT";
    public static final String MINIDEFAULT = "MINIDEFAULT";
    public static final String WGDEFAULT = "WGDEFAULT";
    public static final int INT_100 = 100;
    @Resource
    private WebQuery webQuery;
    @Resource
    private WebPay webPay;
    @Resource
    private GetQrCode getQrCode;
    @Resource
    private CScanBQuery cScanBQuery;
    @Resource
    private UpgQuery upgQuery;
    @Resource
    private UnifiedOrder unifiedOrder;
    @Resource
    private UpgOrder upgOrder;
    @Resource
    private UpgRefund upgRefund;
    @Resource
    private WebRefund webRefund;
    @Resource
    private UnifiedRefund unifiedRefund;
    @Resource
    private CScanBRefund cScanBRefund;
    @Resource
    private WebRefundQuery webRefundQuery;
    @Resource
    private CScanBRefundQuery cScanBRefundQuery;
    @Resource
    private UnifiedRefundQuery unifiedRefundQuery;
    @Resource
    private UpgRefundQuery upgRefundQuery;
    @Resource
    private TransactionOrderService transactionOrderService;
    @Resource
    private ApplyRefundService applyRefundService;
    @Resource
    private UnifiedQuery unifiedQuery;
    @Value("${chinaums.receiveNotify}")
    private String receiveNotify;
    /**
     * 处理新增相关处理
     *
     * @param model 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerSave(ChinaumsLog model) {
        model.setProjectId(ContextUtil.getProjectId());
        model.setSubsystemId(ContextUtil.getSubSystemId());
        model.setTenantId(ContextUtil.getTenantId());
        return R.successDef();
    }

    /**
     * 处理逻辑删除相关处理
     *
     * @param modelList 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerRemoveByIdsOfLogic(Collection<ChinaumsLog> modelList) {
        modelList.stream().forEach(s -> {
            s.setIsDeleted(BusinessConstant.YES);
        });
        // TODO: 2021/10/29 这里需要操作其他业务，如清空角色等
        return R.successDef();
    }

    /**
     * 通用查询
     *
     * @param modelDTO DTO
     * @param ids      主键id集合
     * @return list
     */
    @Override
    public List<ChinaumsLog> list(ChinaumsLogDTO modelDTO, List<Long> ids) {
        return ((ChinaumsLogService) AopContext.currentProxy()).listOfCache(modelDTO, ids);
    }


    /**
     * 缓存查询
     *
     * @param modelDTO DTO
     * @param ids      主键id集合
     * @return list
     */
    @Override
    @Cache(key = "",
            magic = @Magic(
                    key = "{" +
                            "{'isEnabled', #args[0]?.isEnabled}," +
                            "{'orderNum', #args[0]?.orderNum}," +
                            "{'isSuccess', #args[0]?.isSuccess}," +
                            "{'requestUrl', #args[0]?.requestUrl}," +
                            "{'authorization', #args[0]?.authorization}," +
                            "{'requestParameter', #args[0]?.requestParameter}," +
                            "{'responseResults', #args[0]?.responseResults}," +
                            "{'merOrderId', #args[0]?.merOrderId}," +
                            "{'refundOrderId', #args[0]?.refundOrderId}," +
                            "{'id', #args[1]}" +
                            "}"))
    public List<ChinaumsLog> listOfCache(ChinaumsLogDTO modelDTO, List<Long> ids) {
        //查询
        ChinaumsLog queryModel = new ChinaumsLog();
        if (modelDTO != null) {
            BeanUtils.copyProperties(modelDTO, queryModel);
        }
        QueryWrap<ChinaumsLog> wrapper = Wraps.q(queryModel);
        if (ids != null && !ids.isEmpty()) {
            wrapper.lambda().in(ChinaumsLog::getId, ids);
        }
        //添加其他业务查询条件
        wrapper.lambda().eq(ChinaumsLog::getIsDeleted, BusinessConstant.DELETE_NO);
        List<ChinaumsLog> modelList = list(wrapper);
        return modelList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ChinaumsLogVO initiationOfPayments(ChinaumsLogDTO chinaumsLog) throws Exception {
        // 校验支付状态
        ChinaumsLog oldChinaumsLog = checkOrder(chinaumsLog);
        if (Objects.nonNull(oldChinaumsLog)) {
            // 银联的支付链接是30分钟，30分钟内用老得记录
            reusePayLog(chinaumsLog, oldChinaumsLog);
            return BeanUtil.copyProperties(chinaumsLog, ChinaumsLogVO.class);
        }
        // 处理回调地址
        String notifyUrl = String.format("%s?orderNumber=%s&orderType=%s", receiveNotify, chinaumsLog.getOrderNum(), chinaumsLog.getOrderType());
        // 保存日志记录
        ChinaumsDTO initiationOfPaymentsUrl = webPay.getInitiationOfPaymentsUrl(chinaumsLog.getTotalAmount().toString(), chinaumsLog.getReturnUrl(), notifyUrl);
        savePayLog(chinaumsLog, initiationOfPaymentsUrl);
        chinaumsLog.setIsSuccess(BusinessConstant.YES);
        save(BeanUtil.copyProperties(chinaumsLog, ChinaumsLog.class));
        return BeanUtil.copyProperties(chinaumsLog, ChinaumsLogVO.class);

    }

    /**
     * 保存下单支付记录
     * @param chinaumsLog chinaumsLog
     * @param initiationOfPaymentsUrl initiationOfPaymentsUrl
     */
    private void savePayLog(ChinaumsLogDTO chinaumsLog, ChinaumsDTO initiationOfPaymentsUrl) {
        chinaumsLog.setRequestUrl(initiationOfPaymentsUrl.getUrl());
        chinaumsLog.setSignature(initiationOfPaymentsUrl.getSignature());
        chinaumsLog.setAuth(initiationOfPaymentsUrl.getAuthorization());
        chinaumsLog.setMerOrderId(initiationOfPaymentsUrl.getPayBody().getMerOrderId());
        chinaumsLog.setRequestParameter(initiationOfPaymentsUrl.getPayBody().toString());
        chinaumsLog.setRequestType(ChinaumsLogRequestTypeEnum.PAY);
        chinaumsLog.setInstMid(initiationOfPaymentsUrl.getInstMid());
    }

    /**
     * 使用未失效的记录
     * @param chinaumsLog chinaumsLog
     * @param oldChinaumsLog oldChinaumsLog
     */
    private void reusePayLog(ChinaumsLogDTO chinaumsLog, ChinaumsLog oldChinaumsLog) {
        chinaumsLog.setRequestUrl(oldChinaumsLog.getRequestUrl());
        chinaumsLog.setSignature(oldChinaumsLog.getSignature());
        chinaumsLog.setAuth(oldChinaumsLog.getAuth());
        chinaumsLog.setMerOrderId(oldChinaumsLog.getMerOrderId());
        chinaumsLog.setRequestParameter(oldChinaumsLog.getRequestParameter());
        chinaumsLog.setRequestType(ChinaumsLogRequestTypeEnum.PAY);
        chinaumsLog.setInstMid(oldChinaumsLog.getInstMid());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ChinaumsLogVO getPaymentQrCode(ChinaumsLogDTO chinaumsLog) throws Exception {
        ChinaumsLog queryLog = getOne(new QueryWrapper<ChinaumsLog>().lambda()
                .eq(ChinaumsLog::getIsDeleted, BusinessConstant.NO)
                .eq(ChinaumsLog::getOrderNum, chinaumsLog.getOrderNum())
                .eq(Objects.nonNull(chinaumsLog.getOrderType()), ChinaumsLog::getOrderType, chinaumsLog.getOrderType())
                .eq(ChinaumsLog::getRequestType, ChinaumsLogRequestTypeEnum.QUERY));
        // 校验支付状态
        try {
            ChinaumsLog oldChinaumsLog = checkOrder(chinaumsLog);
            if (Objects.nonNull(oldChinaumsLog)) {
                // 银联的支付链接是30分钟，30分钟内用老得记录
                reusePayLog(chinaumsLog, oldChinaumsLog);
                chinaumsLog.setResponseResults(oldChinaumsLog.getResponseResults());
                chinaumsLog.setIsSuccess(BusinessConstant.YES);
                ChinaumsLogVO chinaumsLogVO = BeanUtil.copyProperties(chinaumsLog, ChinaumsLogVO.class);
                chinaumsLogVO.setBillQRCode(JSONObject.parseObject(oldChinaumsLog.getResponseResults()).getString("billQRCode"));
                if (Objects.nonNull(queryLog) && queryLog.getIsSuccess().equals(BusinessConstant.YES)) {
                    chinaumsLogVO.setHasPay(BusinessConstant.YES);
                }
                return chinaumsLogVO;
            }
        } catch (BizException e) {
            log.error("校验失败", e);
            if (PayExceptionCode.TRANSACTION_ORDER_HAS_PAY.getCode() == e.getCode()) {
                ChinaumsLogVO chinaumsLogVO = new ChinaumsLogVO();
                chinaumsLogVO.setHasPay(BusinessConstant.YES);
                return chinaumsLogVO;
            }else if(PayExceptionCode.NO_PAYMENT_REQUIRED.getCode() == e.getCode()){
                // 回填支付状态
                PaymentDTO paymentDTO = new PaymentDTO();
                paymentDTO.setOrderNum(chinaumsLog.getOrderNum());
                paymentDTO.setOrderStatus(TransactionOrderOrderStatusEnum.PAYED);
                paymentDTO.setOrderType(chinaumsLog.getOrderType());
                paymentDTO.setPaymentTime(LocalDateTime.now());
                paymentDTO.setAmount(BigDecimal.valueOf(chinaumsLog.getTotalAmount()).divide(BigDecimal.valueOf(100),2, RoundingMode.HALF_UP));
                paymentDTO.setTransactionSerialNum(chinaumsLog.getMerOrderId());
                // 支付方式 在线支付
                paymentDTO.setPayType(PayTypeEnum.ONLINE_PAY.getCode());
                transactionOrderService.onlinePayment(paymentDTO,chinaumsLog);
                ChinaumsLogVO chinaumsLogVO = new ChinaumsLogVO();
                chinaumsLogVO.setHasPay(BusinessConstant.YES);
                return chinaumsLogVO;
            }else {
                throw e;
            }
        }
        // 处理回调地址
        String notifyUrl = receiveNotify + "?orderNumber=" + chinaumsLog.getOrderNum() + "&orderType=" + chinaumsLog.getOrderType();
        // 保存日志记录
        ChinaumsDTO qrcode = getQrCode.getQrcode(chinaumsLog.getTotalAmount().toString(), chinaumsLog.getReturnUrl(), notifyUrl);
        chinaumsLog.setRequestUrl(qrcode.getUrl());
        chinaumsLog.setSignature(qrcode.getSignature());
        chinaumsLog.setAuth(qrcode.getAuthorization());
        chinaumsLog.setMerOrderId(qrcode.getPayBody().getBillNo());
        chinaumsLog.setRequestParameter(qrcode.getPayBody().toString());
        chinaumsLog.setRequestType(ChinaumsLogRequestTypeEnum.PAY);
        chinaumsLog.setInstMid(qrcode.getInstMid());
        chinaumsLog.setResponseResults(qrcode.getResponse());
        ChinaumsLogVO chinaumsLogVO = BeanUtil.copyProperties(chinaumsLog, ChinaumsLogVO.class);
        // 处理二维码
        if (StringUtils.isNotBlank(qrcode.getResponse())) {
            JSONObject jsonObject = JSONObject.parseObject(qrcode.getResponse());
            chinaumsLogVO.setBillQRCode(jsonObject.getString("billQRCode"));
            if (StringUtils.isNotBlank(chinaumsLogVO.getBillQRCode())) {
                chinaumsLog.setIsSuccess(BusinessConstant.YES);
            }
        }
        save(BeanUtil.copyProperties(chinaumsLog, ChinaumsLog.class));
        // 更新订单状态
        TransactionOrderDTO transactionOrderDTO = new TransactionOrderDTO();
        transactionOrderDTO.setOrderNum(chinaumsLog.getOrderNum());
        transactionOrderDTO.setOrderStatus(TransactionOrderOrderStatusEnum.PAYING);
        transactionOrderService.updateOrderStatus(transactionOrderDTO);
        return chinaumsLogVO;
    }

    @Override
    public ChinaumsLogVO getUpgPayRequest(ChinaumsLogDTO chinaumsLog) throws Exception {
        ChinaumsLog queryLog = getOne(new QueryWrapper<ChinaumsLog>().lambda()
                .eq(ChinaumsLog::getIsDeleted, BusinessConstant.NO)
                .eq(ChinaumsLog::getOrderNum, chinaumsLog.getOrderNum())
                .eq(Objects.nonNull(chinaumsLog.getOrderType()), ChinaumsLog::getOrderType, chinaumsLog.getOrderType())
                .eq(ChinaumsLog::getRequestType, ChinaumsLogRequestTypeEnum.QUERY));
        // 校验支付状态
        try {
            ChinaumsLog oldChinaumsLog = checkOrder(chinaumsLog);
            if (Objects.nonNull(oldChinaumsLog)) {
                // 银联的支付链接是30分钟，30分钟内用老得记录
                reusePayLog(chinaumsLog, oldChinaumsLog);
                chinaumsLog.setResponseResults(oldChinaumsLog.getResponseResults());
                chinaumsLog.setIsSuccess(BusinessConstant.YES);
                ChinaumsLogVO chinaumsLogVO = BeanUtil.copyProperties(chinaumsLog, ChinaumsLogVO.class);
                if (Objects.nonNull(queryLog) && queryLog.getIsSuccess().equals(BusinessConstant.YES)) {
                    chinaumsLogVO.setHasPay(BusinessConstant.YES);
                }
                return chinaumsLogVO;
            }
        } catch (BizException e) {
            log.error("校验失败", e);
            if (PayExceptionCode.TRANSACTION_ORDER_HAS_PAY.getCode() == e.getCode()) {
                ChinaumsLogVO chinaumsLogVO = new ChinaumsLogVO();
                chinaumsLogVO.setHasPay(BusinessConstant.YES);
                return chinaumsLogVO;
            }else {
                throw e;
            }
        }
        // 处理回调地址
        String notifyUrl = receiveNotify + "?orderNumber=" + chinaumsLog.getOrderNum() + "&orderType=" + chinaumsLog.getOrderType();
        // 保存日志记录
        ChinaumsDTO initiationOfPaymentsUrl = upgOrder.getUpgPayRequest(chinaumsLog.getTotalAmount().toString(), chinaumsLog.getReturnUrl(), notifyUrl);
        savePayLog(chinaumsLog, initiationOfPaymentsUrl);
        chinaumsLog.setSubOpenId(chinaumsLog.getSubOpenId());
        chinaumsLog.setResponseResults(initiationOfPaymentsUrl.getResponse());
        ChinaumsLogVO chinaumsLogVO = BeanUtil.copyProperties(chinaumsLog, ChinaumsLogVO.class);
        save(BeanUtil.copyProperties(chinaumsLog, ChinaumsLog.class));
        // 更新订单状态
        TransactionOrderDTO transactionOrderDTO = new TransactionOrderDTO();
        transactionOrderDTO.setOrderNum(chinaumsLog.getOrderNum());
        transactionOrderDTO.setOrderStatus(TransactionOrderOrderStatusEnum.PAYING);
        transactionOrderService.updateOrderStatus(transactionOrderDTO);
        return chinaumsLogVO;

    }

    /**
     * 校验支付状态
     * @param chinaumsLog chinaumsLog
     */
    private ChinaumsLog checkOrder(ChinaumsLogDTO chinaumsLog) {
        // 校验支付状态
        TransactionOrder transactionOrder = transactionOrderService.getByOrderNum(chinaumsLog.getOrderNum());
        if ( Objects.isNull(transactionOrder)) {
            // 找不到对应订单或订单状态为空
            throw BizException.wrap(PayExceptionCode.TRANSACTION_ORDER_NOT_EXIST);
        } else if (TransactionOrderOrderStatusEnum.PAYED.eq(transactionOrder.getOrderStatus())){
            // 已支付
            throw BizException.wrap(PayExceptionCode.TRANSACTION_ORDER_HAS_PAY);
        } else if (!TransactionOrderOrderStatusEnum.UNPAY.eq(transactionOrder.getOrderStatus())
                && !TransactionOrderOrderStatusEnum.PAYING.eq(transactionOrder.getOrderStatus())) {
            // 支付状态不是未支付或支付中，不能发起支付
            throw BizException.wrap(PayExceptionCode.TRANSACTION_ORDER_NOT_PAY);
        } else if (chinaumsLog.getTotalAmount() == 0L) {
            // 金额未0，无需支付
            throw BizException.wrap(PayExceptionCode.NO_PAYMENT_REQUIRED);
        }
        // 处理旧的支付记录
        return cancelOldChinaumsLog(chinaumsLog,ChinaumsLogRequestTypeEnum.PAY);
    }

    /**
     * 作废旧的支付记录
     * @param chinaumsLog 记录
     * @param chinaumsLogRequestTypeEnum 请求类型枚举
     * @return ChinaumsLog
     */
    private ChinaumsLog cancelOldChinaumsLog(ChinaumsLogDTO chinaumsLog, ChinaumsLogRequestTypeEnum chinaumsLogRequestTypeEnum) {
        try{
            // 如果是下单接口，30分钟内有下单记录，则传历史记录，否则删除
            if(chinaumsLogRequestTypeEnum.eq(ChinaumsLogRequestTypeEnum.PAY) ){
                ChinaumsLog one = getOne(new QueryWrapper<ChinaumsLog>().lambda()
                        .eq(ChinaumsLog::getIsDeleted, BusinessConstant.NO)
                        .eq(ChinaumsLog::getOrderNum, chinaumsLog.getOrderNum())
                        .eq(Objects.nonNull(chinaumsLog.getOrderType()), ChinaumsLog::getOrderType, chinaumsLog.getOrderType())
//                        .eq( ChinaumsLog::getIsSuccess, BusinessConstant.YES)
                        .eq(ChinaumsLog::getRequestType, chinaumsLogRequestTypeEnum));
                if(Objects.nonNull(one) && one.getCreateTime().compareTo(LocalDateTime.now().minusMinutes(30L))>0
                        // 并且两次支付金额一致
                        && one.getTotalAmount().equals(chinaumsLog.getTotalAmount())){
//                    String instMid = one.getInstMid();
//                    if(StringUtils.isNotBlank(instMid)){
//                        if(instMid.equals(InstMidEnum.YUEDANDEFAULT.getCode())){
//                            ChinaumsDTO query = webQuery.query(one.getMerOrderId());
//                        }
//                    }
                    // todo 校验订单是否还有效
                    return one;
                }else{
                    // todo 关闭银联订单
                }
            }
            // 作废旧的记录
            update(new UpdateWrapper<ChinaumsLog>().lambda()
                    .eq(ChinaumsLog::getIsDeleted, BusinessConstant.NO)
                    .eq(ChinaumsLog::getOrderNum, chinaumsLog.getOrderNum())
                    .eq(Objects.nonNull(chinaumsLog.getOrderType()), ChinaumsLog::getOrderType, chinaumsLog.getOrderType())
                    .eq(ChinaumsLog::getRequestType, chinaumsLogRequestTypeEnum)
                    .set(ChinaumsLog::getIsDeleted, BusinessConstant.YES));
            return null;
        }catch (Exception e){
            log.error("查询支付记录失败",e);
            throw new BizException(e);
        }
    }

    @Override
    public ChinaumsLogVO queryPayStatus(ChinaumsLogDTO chinaumsLog) {
        log.info("queryPayStatus - 查询支付状态 chinaumsLog：{}",chinaumsLog);
        try {
            ChinaumsLog one = getOne(new QueryWrapper<ChinaumsLog>().lambda()
                    .eq(ChinaumsLog::getIsDeleted, BusinessConstant.NO)
                    .eq(ChinaumsLog::getOrderNum, chinaumsLog.getOrderNum())
                    .eq(Objects.nonNull(chinaumsLog.getOrderType()),ChinaumsLog::getOrderType,chinaumsLog.getOrderType())
                    .eq(ChinaumsLog::getRequestType, ChinaumsLogRequestTypeEnum.PAY));
            if (Objects.nonNull(one)) {
                // 作废旧的
                cancelOldChinaumsLog(chinaumsLog,ChinaumsLogRequestTypeEnum.QUERY);
                // 判断银联业务类型
                String instMid = one.getInstMid();
                ChinaumsDTO chinaumsDTO = null;
                if(StringUtils.isNotBlank(instMid) && instMid.equals(QRPAYDEFAULT)){
                    // 二维码支付
                    JSONObject requestParameterObj = JSONObject.parseObject(one.getRequestParameter());
                    chinaumsDTO = cScanBQuery.query(requestParameterObj.getString("billNo"), requestParameterObj.getString("billDate"));
                    return dealCScanBQuery(chinaumsLog, chinaumsDTO);
                }else if(StringUtils.isNotBlank(instMid) && instMid.equals(WGDEFAULT)){
                    // 网关支付
                    chinaumsDTO = upgQuery.query(one.getMerOrderId());
                    return dealWebQuery(chinaumsLog, chinaumsDTO);
                }else if(StringUtils.isNotBlank(instMid) && instMid.equals(MINIDEFAULT)){
                    // 小程序支付
                    chinaumsDTO = unifiedQuery.query(one.getMerOrderId());
                    return dealWebQuery(chinaumsLog, chinaumsDTO);
                }else{
                    // 公众号
                    chinaumsDTO = webQuery.query(one.getMerOrderId());
                    return dealWebQuery(chinaumsLog, chinaumsDTO);
                }
            }
        } catch (Exception e) {
            log.error("查询支付状态失败", e);
        }
        return null;
    }

    /**
     * 处理公众号支付
     * @param chinaumsLog chinaumsLog
     * @param chinaumsDTO chinaumsDTO
     * @return ChinaumsLogVO
     */
    private ChinaumsLogVO dealWebQuery(ChinaumsLogDTO chinaumsLog, ChinaumsDTO chinaumsDTO) throws Exception {
        chinaumsLog.setRequestUrl(chinaumsDTO.getUrl());
        chinaumsLog.setAuth(chinaumsDTO.getAuthorization());
        chinaumsLog.setSignature(chinaumsDTO.getSignature());
        chinaumsLog.setMerOrderId(chinaumsDTO.getQueryBody().getMerOrderId());
        chinaumsLog.setRequestParameter(chinaumsDTO.getQueryBody().toString());
        chinaumsLog.setRequestType(ChinaumsLogRequestTypeEnum.QUERY);
        chinaumsLog.setResponseResults(chinaumsDTO.getResponse());
        chinaumsLog.setInstMid(chinaumsDTO.getInstMid());
        // 处理银联返回
        JSONObject jsonObject = JSONObject.parseObject(chinaumsDTO.getResponse());
        Object status = jsonObject.get("status");
        Object targetSys = jsonObject.get("targetSys");
        if (Objects.nonNull(status) && status.toString().equals(ChinaumsStatusEnum.TRADE_SUCCESS.getCode())) {
            // 支付成功，未进入退款流程
            chinaumsLog.setIsSuccess(BusinessConstant.YES);
            PaymentDTO paymentDTO = new PaymentDTO();
            paymentDTO.setOrderNum(chinaumsLog.getOrderNum());
            paymentDTO.setOrderStatus(TransactionOrderOrderStatusEnum.PAYED);
            paymentDTO.setOrderType(chinaumsLog.getOrderType());
            paymentDTO.setPaymentTime(LocalDateTimeUtil.parse(jsonObject.get("payTime").toString(),"yyyy-MM-dd HH:mm:ss"));
            paymentDTO.setAmount(BigDecimal.valueOf(Integer.parseInt(jsonObject.get("totalAmount").toString())).divide(BigDecimal.valueOf(100),2, RoundingMode.HALF_UP));
            paymentDTO.setTransactionSerialNum(chinaumsLog.getMerOrderId());
            // 支付方式 在线支付
            paymentDTO.setPayType(PayTypeEnum.ONLINE_PAY.getCode());
            // 支付渠道
            if(Objects.nonNull(targetSys)){
                paymentDTO.setPayChannel(targetSys.toString());
            }
            transactionOrderService.onlinePayment(paymentDTO, chinaumsLog);
        }else if(Objects.nonNull(status) && status.toString().equals(ChinaumsStatusEnum.WAIT_BUYER_PAY.getCode())){
            // 等待支付

        }else if(Objects.nonNull(status) && status.toString().equals(ChinaumsStatusEnum.TRADE_REFUND.getCode())){
            // 进入了退款流程
            chinaumsLog.setIsSuccess(BusinessConstant.YES);
            queryRefund(chinaumsLog);
        }
        save(BeanUtil.copyProperties(chinaumsLog, ChinaumsLog.class));
        return BeanUtil.copyProperties(chinaumsLog, ChinaumsLogVO.class);
    }

    /**
     * 处理c扫b的查询返回
     * @param chinaumsLog chinaumsLog
     * @param chinaumsDTO chinaumsDTO
     * @return ChinaumsLogVO
     */
    private ChinaumsLogVO dealCScanBQuery(ChinaumsLogDTO chinaumsLog, ChinaumsDTO chinaumsDTO) throws Exception {
        chinaumsLog.setRequestUrl(chinaumsDTO.getUrl());
        chinaumsLog.setAuth(chinaumsDTO.getAuthorization());
        chinaumsLog.setSignature(chinaumsDTO.getSignature());
        chinaumsLog.setMerOrderId(chinaumsDTO.getQueryBody().getBillNo());
        chinaumsLog.setRequestParameter(chinaumsDTO.getQueryBody().toString());
        chinaumsLog.setRequestType(ChinaumsLogRequestTypeEnum.QUERY);
        chinaumsLog.setResponseResults(chinaumsDTO.getResponse());
        chinaumsLog.setInstMid(chinaumsDTO.getInstMid());
        // 处理银联返回
        JSONObject jsonObject = JSONObject.parseObject(chinaumsDTO.getResponse()).getJSONObject("billPayment");
        Object status = jsonObject.get("status");
        Object targetSys = jsonObject.get("targetSys");
        if (Objects.nonNull(status) && status.toString().equals(ChinaumsStatusEnum.TRADE_SUCCESS.getCode())) {
            // 支付成功，未进入退款流程
            chinaumsLog.setIsSuccess(BusinessConstant.YES);
            PaymentDTO paymentDTO = new PaymentDTO();
            paymentDTO.setOrderNum(chinaumsLog.getOrderNum());
            paymentDTO.setOrderStatus(TransactionOrderOrderStatusEnum.PAYED);
            paymentDTO.setOrderType(chinaumsLog.getOrderType());
            paymentDTO.setPaymentTime(LocalDateTimeUtil.parse(jsonObject.get("payTime").toString(),"yyyy-MM-dd HH:mm:ss"));
            paymentDTO.setAmount(BigDecimal.valueOf(Integer.parseInt(jsonObject.get("totalAmount").toString())).divide(BigDecimal.valueOf(100),2, RoundingMode.HALF_UP));
            paymentDTO.setTransactionSerialNum(chinaumsLog.getMerOrderId());
            chinaumsLog.setTotalAmount(Long.parseLong(jsonObject.get("totalAmount").toString()));
            // 支付方式 在线支付
            paymentDTO.setPayType(PayTypeEnum.ONLINE_PAY.getCode());
            // 支付渠道
            if(Objects.nonNull(targetSys)){
                paymentDTO.setPayChannel(targetSys.toString());
            }
            transactionOrderService.onlinePayment(paymentDTO,chinaumsLog);
        }else if(Objects.nonNull(status) && status.toString().equals(ChinaumsStatusEnum.WAIT_BUYER_PAY.getCode())){
            // 等待支付

        }else if(Objects.nonNull(status) && status.toString().equals(ChinaumsStatusEnum.TRADE_REFUND.getCode())){
            // 进入了退款流程
            chinaumsLog.setIsSuccess(BusinessConstant.YES);
            queryRefund(chinaumsLog);
        }
        save(BeanUtil.copyProperties(chinaumsLog, ChinaumsLog.class));
        return BeanUtil.copyProperties(chinaumsLog, ChinaumsLogVO.class);
    }

    @Override
    public ChinaumsLogVO refund(ChinaumsLogDTO chinaumsLog) {
        log.info("refund - 退款 chinaumsLog：{}",chinaumsLog);
        try {
            // 查询旧的退款记录
            ChinaumsLog refundChinaumsLog = getOne(new QueryWrapper<ChinaumsLog>().lambda()
                    .eq(ChinaumsLog::getIsDeleted, BusinessConstant.NO)
                    .eq(ChinaumsLog::getOrderNum, chinaumsLog.getOrderNum())
                    .eq(Objects.nonNull(chinaumsLog.getOrderType()),ChinaumsLog::getOrderType,chinaumsLog.getOrderType())
                    .eq(ChinaumsLog::getIsSuccess, BusinessConstant.YES)
                    .eq(ChinaumsLog::getRequestType, ChinaumsLogRequestTypeEnum.REFUND));
            if(Objects.nonNull(refundChinaumsLog)){
                return BeanUtil.copyProperties(refundChinaumsLog, ChinaumsLogVO.class);
            }else {
                ChinaumsLog one = getOne(new QueryWrapper<ChinaumsLog>().lambda()
                        .eq(ChinaumsLog::getIsDeleted, BusinessConstant.NO)
                        .eq(ChinaumsLog::getOrderNum, chinaumsLog.getOrderNum())
                        .eq(Objects.nonNull(chinaumsLog.getOrderType()),ChinaumsLog::getOrderType,chinaumsLog.getOrderType())
                        .eq(ChinaumsLog::getRequestType, ChinaumsLogRequestTypeEnum.PAY));
                if (Objects.nonNull(one)) {
                    Long totalAmount = one.getTotalAmount();
                    // 作废旧的
                    cancelOldChinaumsLog(chinaumsLog,ChinaumsLogRequestTypeEnum.REFUND);
                    // 判断下单记录的银联支付类型
                    String instMid = one.getInstMid();
                    ChinaumsDTO refund = new ChinaumsDTO();
                    if(InstMidEnum.YUEDANDEFAULT.getCode().equals(instMid)){
                        refund = webRefund.refund(one.getMerOrderId(), String.valueOf(totalAmount));
                    }else if(InstMidEnum.QRPAYDEFAULT.getCode().equals(instMid)){
                        refund = cScanBRefund.refund(one, String.valueOf(totalAmount));
                    }else if(InstMidEnum.MINIDEFAULT.getCode().equals(instMid)){
                        refund = unifiedRefund.refund(one.getMerOrderId(), String.valueOf(totalAmount));
                    }else if(InstMidEnum.WGDEFAULT.getCode().equals(instMid)){
                        refund = upgRefund.refund(one.getMerOrderId(), String.valueOf(totalAmount));
                    }
                    chinaumsLog.setRequestUrl(refund.getUrl());
                    chinaumsLog.setAuth(refund.getAuthorization());
                    chinaumsLog.setSignature(refund.getSignature());
                    chinaumsLog.setMerOrderId(refund.getRefundBody().getMerOrderId());
                    chinaumsLog.setRefundOrderId(refund.getRefundBody().getRefundOrderId());
                    chinaumsLog.setRequestParameter(refund.getRefundBody().toString());
                    chinaumsLog.setRefundAmount(totalAmount);
                    chinaumsLog.setRequestType(ChinaumsLogRequestTypeEnum.REFUND);
                    chinaumsLog.setResponseResults(refund.getResponse());
                    chinaumsLog.setInstMid(refund.getInstMid());
                    JSONObject jsonObject = JSONObject.parseObject(refund.getResponse());
                    Object refundStatus = jsonObject.get("refundStatus");
                    if(Objects.nonNull(refundStatus) && refundStatus.equals(SUCCESS)){
                        chinaumsLog.setIsSuccess(BusinessConstant.YES);
                    }
                    save(BeanUtil.copyProperties(chinaumsLog, ChinaumsLog.class));
                    return BeanUtil.copyProperties(chinaumsLog, ChinaumsLogVO.class);
                }
            }
        } catch (Exception e) {
            log.error("退款失败", e);
        }
        return null;
    }

    @Override
    public ChinaumsLogVO queryRefund(ChinaumsLogDTO chinaumsLog) throws Exception {
            ChinaumsLog one = getOne(new QueryWrapper<ChinaumsLog>().lambda()
                    .eq(ChinaumsLog::getIsDeleted, BusinessConstant.NO)
                    .eq(ChinaumsLog::getOrderNum, chinaumsLog.getOrderNum())
                    .eq(Objects.nonNull(chinaumsLog.getOrderType()),ChinaumsLog::getOrderType,chinaumsLog.getOrderType())
                    .eq(ChinaumsLog::getRequestType, ChinaumsLogRequestTypeEnum.REFUND));
            if (Objects.nonNull(one)) {
                // 作废旧的
                cancelOldChinaumsLog(chinaumsLog,ChinaumsLogRequestTypeEnum.REFUND_QUERY);
                // 判断下单记录的银联支付类型
                String instMid = one.getInstMid();
                ChinaumsDTO chinaumsDTO = new ChinaumsDTO();
                if(InstMidEnum.YUEDANDEFAULT.getCode().equals(instMid)){
                    chinaumsDTO = webRefundQuery.refundQuery(one.getRefundOrderId());
                }else if(InstMidEnum.QRPAYDEFAULT.getCode().equals(instMid)){
                    chinaumsDTO = cScanBRefundQuery.refundQuery(one.getRefundOrderId());
                }else if(InstMidEnum.MINIDEFAULT.getCode().equals(instMid)){
                    chinaumsDTO = unifiedRefundQuery.refundQuery(one.getMerOrderId());
                }else if(InstMidEnum.WGDEFAULT.getCode().equals(instMid)){
                    chinaumsDTO = upgRefundQuery.refundQuery(one.getMerOrderId());
                }
                chinaumsLog.setRequestUrl(chinaumsDTO.getUrl());
                chinaumsLog.setAuth(chinaumsDTO.getAuthorization());
                chinaumsLog.setSignature(chinaumsDTO.getSignature());
                chinaumsLog.setMerOrderId(one.getMerOrderId());
                chinaumsLog.setRefundOrderId(chinaumsDTO.getRefundQueryBody().getMerOrderId());
                chinaumsLog.setRequestParameter(chinaumsDTO.getRefundQueryBody().toString());
                chinaumsLog.setRequestType(ChinaumsLogRequestTypeEnum.REFUND_QUERY);
                chinaumsLog.setResponseResults(chinaumsDTO.getResponse());
                chinaumsLog.setOrderType(chinaumsLog.getOrderType());
                chinaumsLog.setInstMid(one.getInstMid());
                save(BeanUtil.copyProperties(chinaumsLog, ChinaumsLog.class));
                // 处理支付中心状态
                JSONObject jsonObject = JSONObject.parseObject(chinaumsDTO.getResponse());
                String refundStatus = jsonObject.getString("refundStatus");
                if(StringUtils.isNotBlank(refundStatus) && refundStatus.equals(SUCCESS)){
                    RefundDTO refundDTO = new RefundDTO();
                    refundDTO.setOrderNum(chinaumsLog.getOrderNum());
                    refundDTO.setOrderType(chinaumsLog.getOrderType());
                    refundDTO.setRefundTime(one.getCreateTime());
                    refundDTO.setRefundStatus(RefundStatusEnum.IS_REFUND);
                    refundDTO.setAmount(BigDecimal.valueOf(Integer.parseInt(jsonObject.get("refundInvoiceAmount").toString())).divide(BigDecimal.valueOf(100),2, RoundingMode.HALF_UP));
                    refundDTO.setTransactionSerialNum(jsonObject.getString("refundOrderId"));
                    applyRefundService.onlineRefund(refundDTO);
                }
                return BeanUtil.copyProperties(chinaumsLog, ChinaumsLogVO.class);
            }else {
                log.error(PayExceptionCode.APPLY_REFUND_DOES_NOT_EXIST.getMsg());
                throw BizException.wrap(PayExceptionCode.APPLY_REFUND_DOES_NOT_EXIST);
            }
    }

    @Override
    public ChinaumsLogVO getMiniPayRequest(ChinaumsLogDTO chinaumsLog) throws Exception {
        ChinaumsLog queryLog = getOne(new QueryWrapper<ChinaumsLog>().lambda()
                .eq(ChinaumsLog::getIsDeleted, BusinessConstant.NO)
                .eq(ChinaumsLog::getOrderNum, chinaumsLog.getOrderNum())
                .eq(Objects.nonNull(chinaumsLog.getOrderType()), ChinaumsLog::getOrderType, chinaumsLog.getOrderType())
                .eq(ChinaumsLog::getRequestType, ChinaumsLogRequestTypeEnum.QUERY));
        // 校验支付状态
        try {
            ChinaumsLog oldChinaumsLog = checkOrder(chinaumsLog);
            if (Objects.nonNull(oldChinaumsLog)) {
                // 银联的支付链接是30分钟，30分钟内用老得记录
                reusePayLog(chinaumsLog, oldChinaumsLog);
                chinaumsLog.setResponseResults(oldChinaumsLog.getResponseResults());
                chinaumsLog.setIsSuccess(BusinessConstant.YES);
                ChinaumsLogVO chinaumsLogVO = BeanUtil.copyProperties(chinaumsLog, ChinaumsLogVO.class);
                if (Objects.nonNull(queryLog) && queryLog.getIsSuccess().equals(BusinessConstant.YES)) {
                    chinaumsLogVO.setHasPay(BusinessConstant.YES);
                }
                chinaumsLogVO.setMiniPayRequest(JSONObject.parseObject(chinaumsLogVO.getResponseResults()).getString("miniPayRequest"));
                return chinaumsLogVO;
            }
        } catch (BizException e) {
            log.error("校验失败", e);
            if (PayExceptionCode.TRANSACTION_ORDER_HAS_PAY.getCode() == e.getCode()) {
                ChinaumsLogVO chinaumsLogVO = new ChinaumsLogVO();
                chinaumsLogVO.setHasPay(BusinessConstant.YES);
                return chinaumsLogVO;
            } else {
                throw e;
            }
        }
        // 处理回调地址
        String notifyUrl = receiveNotify + "?orderNumber=" + chinaumsLog.getOrderNum() + "&orderType=" + chinaumsLog.getOrderType();
        // 保存日志记录
        ChinaumsDTO initiationOfPaymentsUrl = unifiedOrder.getMiniPayRequest(chinaumsLog.getTotalAmount().toString(), chinaumsLog.getReturnUrl(), notifyUrl, chinaumsLog.getSubOpenId(), chinaumsLog.getSubAppId());
        savePayLog(chinaumsLog, initiationOfPaymentsUrl);
        chinaumsLog.setSubOpenId(chinaumsLog.getSubOpenId());
        chinaumsLog.setResponseResults(initiationOfPaymentsUrl.getResponse());
        ChinaumsLogVO chinaumsLogVO = BeanUtil.copyProperties(chinaumsLog, ChinaumsLogVO.class);
        chinaumsLogVO.setMiniPayRequest(JSONObject.parseObject(chinaumsLogVO.getResponseResults()).getString("miniPayRequest"));
        if (StringUtils.isNotBlank(chinaumsLogVO.getMiniPayRequest())) {
            chinaumsLog.setIsSuccess(BusinessConstant.YES);
        }
        save(BeanUtil.copyProperties(chinaumsLog, ChinaumsLog.class));
        // 更新订单状态
        TransactionOrderDTO transactionOrderDTO = new TransactionOrderDTO();
        transactionOrderDTO.setOrderNum(chinaumsLog.getOrderNum());
        transactionOrderDTO.setOrderStatus(TransactionOrderOrderStatusEnum.PAYING);
        transactionOrderService.updateOrderStatus(transactionOrderDTO);
        return chinaumsLogVO;
    }

    /**
     * do转vo
     *
     * @param model model
     * @return modelVo
     */
    @Override
    public ChinaumsLogVO doToVo(ChinaumsLog model) {
        ChinaumsLogVO modelVo = new ChinaumsLogVO();
        BeanUtils.copyProperties(model, modelVo);
        modelVo.setId(model.getId());
        return modelVo;
    }

    /**
     * do转vo
     *
     * @param modelList modelList
     * @return list
     */
    @Override
    public List<ChinaumsLogVO> doToVos(List<ChinaumsLog> modelList) {
        if (modelList == null || modelList.isEmpty()) {
            return null;
        }
        List<ChinaumsLogVO> result = new ArrayList<>();
        for (ChinaumsLog model : modelList) {
            result.add(doToVo(model));
        }
        return result;
    }
}
